<template>
    <view class="index-list">
        <view v-if="showSidebar" class="sidebar l-sidebar-class" @tap.stop.prevent="onTapSidebar" @touchmove.stop.prevent="onTouchMove" @touchend.stop.prevent="onTouchend">
            <block v-for="(sidebarItem, index) in sidebarData" :key="index">
                <view :class="'sidebar-item l-sidebar-item-class ' + (activeSidebarItem === index ? 'sidebar-item-active l-selected-class' : 'l-unselected-class')">
                    {{ sidebarItem }}
                </view>
            </block>

            <view
                class="tip l-tip-class"
                :style="'top:' + tipTop + 'px;' + (showTip ? '' : 'opacity:0;') + 'transform: rotate(-45deg) translateY(' + (-tipHeight / 2 - tipHeightOverflow) + 'px);'"
            >
                <view class="tip-text l-tip-text-class">{{ tipText }}</view>
            </view>
        </view>

        <slot></slot>
    </view>
</template>

<script>
import nodeUtil from '../core/utils/node-util';
import dataUtil from '../core/utils/data-util';
import eventUtil from '../core/utils/event-util';
import pixelUtil from '../core/utils/pixel-util';
const defaultSidebarData = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
export default {
    unicomGroup: ['index-anchor'],
    data() {
        return {
            _sidebar: {
                top: 0,
                height: 0,
                sidebarItemCenterPoints: [],
                isMoving: false,
                sidebarItemRect: {},
                sidebarItemHeight: '',
                sidebarItemRealHeight: ''
            },

            _anchor: {
                anchorTopLocations: [],
                indexAnchorComponents: [],
                currentStickAnchorIndex: -1,
                anchorItemsHeight: []
            },

            _stickOffsetTopPx: 0,
            activeSidebarItem: 0,
            tipTop: 0,
            showTip: false,
            tipHeight: 0,
            sidebarItem: '',
            tipHeightOverflow: 0,
            tipText: ''
        };
    },
    externalClasses: ['l-tip-class', 'l-tip-text-class', 'l-sidebar-class', 'l-selected-class', 'l-unselected-class', 'l-sidebar-item-class'],
    relations: {
        '../index-anchor/index': {
            type: 'child'
        }
    },
    options: {
        multipleSlots: true,
        pureDataPattern: /^_/
    },
    mounted() {
        // 处理小程序 attached 生命周期
        this.attached();
    },
    props: {
        isStick: {
            type: Boolean,
            default: false
        },
        scrollTop: {
            type: Number,
            default: 0
        },
        sidebarData: {
            type: Array,
            default: defaultSidebarData
        },
        showSidebar: {
            type: Boolean,
            default: true
        },
        stickOffsetTop: {
            type: Number,
            default: 0
        }
    },
    watch: {
        scrollTop: function (t) {
            this.setIndexListStyle(t);
        },
        stickOffsetTop: function (t) {
            this.setData({
                _stickOffsetTopPx: pixelUtil.rpx2px(t)
            });
        }
    },
    methods: {
        attached() {
            this.init();
        },

        async init() {
            await this.parseSidebarRect();
            await this.parseSidebarItemRect();
            await this.parseIndexAnchors();
            this.parseAnchorRect();
            uni.lin = uni.lin || {};
            uni.lin.setScrollTop = (t) => {
                dataUtil.setDiffData(this, {
                    scrollTop: t
                });
            };
        },

        async parseSidebarRect() {
            const t = await nodeUtil.getNodeRectFromComponent(this, '.sidebar');
            this.setData({
                '_sidebar.height': t.height,
                '_sidebar.top': t.top
            });
        },

        async parseSidebarItemRect() {
            const t = this.sidebarData.length;
            const e = await nodeUtil.getNodeRectFromComponent(this, '.sidebar-item');
            const i = this._sidebar.height / t;
            const a = e.height;
            const s = await nodeUtil.getNodeFieldsFromComponent(this, '.sidebar-item', {
                computedStyle: ['margin-top']
            });
            const o = await nodeUtil.getNodeFieldsFromComponent(this, '.tip', {
                computedStyle: ['height']
            });
            const n = [];
            const r = s['margin-top'].replace('px', '');
            for (let e = 1; e <= t; e++) {
                n.push(((2 * e - 1) * a) / 2 + e * parseInt(r));
            }
            const h = parseInt(o.height.replace('px', ''));
            this.setData({
                tipHeight: h,
                tipHeightOverflow: 0.205 * h,
                '_sidebar.sidebarItemRect': e,
                '_sidebar.sidebarItemHeight': i,
                '_sidebar.sidebarItemRealHeight': a,
                '_sidebar.sidebarItemCenterPoints': n
            });
        },

        parseIndexAnchors() {
            const t = this.getRelationNodes('index-anchor');
            if (t) {
                this.setData({
                    '_anchor.indexAnchorComponents': t
                });
                for (let e = 0; e < t.length; e++) {
                    t[e].setData({
                        anchorText: this.sidebarData[e]
                    });
                }
            } else {
                console.error('获取 index-anchor 节点实例失败，请参考文档检查您的代码是否书写正确');
            }
        },

        async parseAnchorRect() {
            const t = [];
            const e = [];
            const i = this._anchor.indexAnchorComponents;
            for (const a of i) {
                const i = await nodeUtil.getNodeRectFromComponent(a, '.anchor');
                if (null !== i) {
                    t.push(i.top);
                    e.push(i.height);
                }
            }
            this.setData({
                '_anchor.anchorTopLocations': t,
                '_anchor.anchorItemsHeight': e
            });
        },

        switchTipShow(t) {
            dataUtil.setDiffData(this, {
                showTip: t
            });
        },

        switchSidebarIndex(t) {
            dataUtil.setDiffData(this, {
                activeSidebarItem: t
            });
        },

        switchIsMovingSidebar(t) {
            dataUtil.setDiffData(this, {
                '_sidebar.isMoving': t
            });
        },

        setIndexListStyle(t) {
            const e = this.countCurrentActiveIndex(t);
            if (void 0 !== e) {
                if (this.isStick) {
                    this.setAnchorStyle(t);
                }
                if (this.showSidebar && !this._sidebar.isMoving) {
                    this.switchSidebarIndex(e);
                }
            }
        },

        setAnchorStyle(t) {
            const { anchorTopLocations: e, anchorItemsHeight: i, indexAnchorComponents: a } = this._anchor;
            const s = this.countCurrentActiveIndex(t);
            const o = a[s];
            const n = e[s];
            const r = i[s];
            const h = e[s + 1];
            const c = this._stickOffsetTopPx;
            if (t + c >= n && t + c <= h - r && !o.isFixed()) {
                o.setFixed(this.stickOffsetTop, r);
                for (let t = 0; t < a.length; t++) {
                    if (t !== s) {
                        a[t].clearStyle();
                    }
                }
            } else if (t + c > h - r && t + c < h && !o.isRelative()) {
                o.setRelative(h - n - r);
                for (let t = 0; t < a.length; t++) {
                    if (t !== s) {
                        a[t].clearStyle();
                    }
                }
            } else if (t + c < n) {
                for (let t = 0; t < a.length; t++) {
                    a[t].clearStyle();
                }
            }
        },

        countCurrentActiveIndex(t) {
            let e = 0;
            const { anchorTopLocations: i } = this._anchor;
            for (let a = 0; a < i.length; a++) {
                if (t + this._stickOffsetTopPx < i[a]) {
                    e = a - 1;
                    break;
                }
            }
            if (e < 0) {
                e = 0;
            }
            return e;
        },

        onTouchMove(t) {
            this.switchTipShow(true);
            this.switchIsMovingSidebar(true);
            const { top: e, sidebarItemHeight: i } = this._sidebar;
            const a = this.sidebarData.length;
            const s = t.touches[0].clientY;
            let o = Math.floor((s - e) / i);
            if (o < 0) {
                o = 0;
            } else {
                if (o > a - 1) {
                    o = a - 1;
                }
            }
            const n = this.sidebarData[o];
            dataUtil.setDiffData(this, {
                tipText: n,
                activeSidebarItem: o,
                tipTop: this._sidebar.sidebarItemCenterPoints[o]
            });
            let r = this._anchor.anchorTopLocations[o] - this._stickOffsetTopPx;
            uni.pageScrollTo({
                duration: 0,
                scrollTop: r
            });
            eventUtil.emit(this, 'linselected', {
                index: o,
                tipText: n
            });
        },

        onTouchend() {
            setTimeout(() => {
                this.switchTipShow(false);
            }, 500);
            this.switchIsMovingSidebar(false);
        },

        onTapSidebar(t) {
            this.onTouchMove(t);
        }
    },
    created: function () {}
};
</script>
<style>
.index-list .sidebar {
    font-size: 24rpx;
    position: fixed;
    right: 30rpx;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
}
.index-list .sidebar-item {
    width: 40rpx;
    height: 40rpx;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 8rpx;
}
.index-list .sidebar-item-active {
    color: #fff;
    background-color: #3963bc;
}
.index-list .tip {
    width: 90rpx;
    height: 90rpx;
    background-color: #d8d8d8;
    border-radius: 90px 90px 0;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: -160rpx;
    transform: rotate(-45deg) translateY(-35%);
}
.index-list .tip-text {
    font-size: 30rpx;
    transform: rotate(45deg);
}
</style>
